/**
 *
 */
package cn.hg.jbsa.admin.controller.system;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;

import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.Kv;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.ehcache.IDataLoader;

import cn.hg.jboot.core.constant.BaseConstants;
import cn.hg.jbsa.admin.controller.BaseJbsaAdminController;
import cn.hg.jbsa.admin.controller.system.validator.JbsaOrgRoleValidator;
import cn.hg.jbsa.admin.controller.system.validator.JbsaResourceValidator;
import cn.hg.jbsa.admin.model.JbsaAdmin;
import cn.hg.jbsa.admin.model.JbsaOrg;
import cn.hg.jbsa.admin.model.JbsaOrgRole;
import cn.hg.jbsa.admin.model.JbsaRole;
import cn.hg.jbsa.admin.service.JbsaOrgRoleService;
import cn.hg.jbsa.admin.service.JbsaOrgService;
import cn.hg.jbsa.admin.service.JbsaRoleService;
import cn.hg.jbsa.common.annotation.JbsaLog;
import cn.hg.jbsa.common.constant.JbsaConstants;
import cn.hg.jbsa.common.web.LayuiPage;
import cn.hg.jbsa.common.web.LayuiTransferData;
import cn.hg.jbsa.common.web.LayuiTreeSelect;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.jboot.components.cache.annotation.CacheEvict;
import io.jboot.db.model.Columns;
import io.jboot.utils.CacheUtil;
import io.jboot.web.controller.annotation.DeleteRequest;
import io.jboot.web.controller.annotation.GetRequest;
import io.jboot.web.controller.annotation.PostRequest;
import io.jboot.web.controller.annotation.RequestMapping;

/**
 * @author Golly
 */
@RequestMapping(value = "/admin/system/org")
public class JbsaOrgController extends BaseJbsaAdminController {
    private static String SERVICE_NAME = "部门";

    private Log LOG = Log.getLog(JbsaOrgController.class);

    /**
     * 服务实例
     */
    @Inject
    private JbsaOrgService orgService;

    @Inject
    private JbsaRoleService roleService;

    @Inject
    private JbsaOrgRoleService orgRoleService;

    /**
     * 跳转到新增页面
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:add"})
    public void add() {
        this.LOG.info("跳转到新增{}页面", SERVICE_NAME);

        JbsaOrg bean = new JbsaOrg();
        bean.setParentId(this.getInt(0));

        this.setAttr("bean", bean);
    }

    /**
     * 跳转到指派角色页面
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:assignRole"})
    public void assignRole() {
        this.LOG.info("跳转到{}指派角色页面：kv={}", SERVICE_NAME, this.getKv());

        // 所有角色对象
        List<JbsaRole> roleList = this.roleService.findListByColumns(Columns.create("status", "on"));
        // Org的角色对象
        JbsaOrgRole bean = this.orgRoleService.findFirstByColumns(Columns.create("org_id", this.get(0)));

        if (ObjectUtil.isNull(bean)) {
            bean = new JbsaOrgRole();
            bean.setOrgId(this.getInt(0));
        }

        this.setAttr("roleData", JsonKit.toJson(new LayuiTransferData<>(roleList, "name", "id")));
        this.setAttr("bean", bean);
    }

    /**
     * 批量删除功能
     */
    @CacheEvict(name = JbsaConstants.CACHE_NAME_ORG)
    @DeleteRequest
    @RequiresPermissions(value = {"system:org:del"})
    @JbsaLog("批量删除部门")
    public void batchDelete() {
        this.LOG.info("{}批量删除功能：kv={}", SERVICE_NAME, this.getKv());
        Object[] ids = CharSequenceUtil.split(this.get(0), ',').toArray();

        for (Object id : ids) {
            JbsaOrg bean = this.orgService.findById(id);
            if (ObjectUtil.isNotNull(bean)) {
                bean.setStatus("del");
                this.orgService.update(bean);
            }
        }

        this.renderAjaxSuccessed();
    }

    /**
     * 删除记录功能
     */
    @CacheEvict(name = JbsaConstants.CACHE_NAME_ORG)
    @DeleteRequest
    @RequiresPermissions(value = {"system:org:del"})
    @JbsaLog("删除部门")
    public void delete() {
        this.LOG.info("{}删除记录功能：kv={}", SERVICE_NAME, this.getKv());

        JbsaOrg bean = this.orgService.findById(this.get(0));

        // 记录不存在则报错
        if (ObjectUtil.isNull(bean)) {
            this.renderAjaxFailed("记录不存在！");
            return;
        }

        bean.setStatus("del");

        this.orgService.update(bean);

        this.renderAjaxSuccessed();
    }

    /**
     * 执行指派角色操作
     */
    @CacheEvict(name = JbsaConstants.CACHE_NAME_ORG_ROLE)
    @Before(JbsaOrgRoleValidator.class)
    @PostRequest
    @RequiresPermissions(value = {"system:org:assignRole"})
    @JbsaLog("为部门指派角色")
    public void doAssignRole(JbsaOrgRole bean) {
        this.LOG.info("执行{}指派角色操作：kv={}", SERVICE_NAME, this.getKv());

        try {
            Object id = this.orgRoleService.saveOrUpdate(bean);
            if (ObjectUtil.isNull(id)) {
                this.renderAjaxFailed(BaseConstants.RETURN_CODE_VALUE_FAILED, "执行指派角色操作发生异常！");
            } else {
                this.renderAjaxSuccessed();
            }
        } catch (Throwable t) {
            this.LOG.error(CharSequenceUtil.format("执行指派角色操作时发生异常：bean={}", bean), t);
            this.renderAjaxFailed(t.getMessage());
        }
    }

    /**
     * 跳转到编辑页面
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:edit"})
    public void edit() {
        this.LOG.info("跳转到{}编辑页面", SERVICE_NAME);

        JbsaOrg bean = this.orgService.findById(this.get(0));
        this.setAttr("bean", bean);
    }

    /**
     * 跳转到列表页面
     */
    @Override
    @GetRequest
    @RequiresAuthentication
    public void index() {
        this.LOG.info("跳转到{}列表页面", SERVICE_NAME);
    }

    /**
     * 分页查询功能
     * 
     * @param page
     *            页号
     * @param limit
     *            页大小
     * @param sortField
     *            排序字段
     * @param sortType
     *            排序类型：asc或desc
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:list"})
    public void list(Integer page, Integer limit, String sortField, String sortType) {
        this.LOG.info("{}分页查询功能：kv={}", SERVICE_NAME, this.getKv());

        /*
         * 建立查询键值对
         */
        Kv para = this.getKv()
            // 标准参数
            .set("sortField", CharSequenceUtil.toUnderlineCase(sortField))
            // 其它参数
            .set("admin", this.getCurrentAdmin())
            ;

        /*
         * 调用服务模块执行查询，并处理缓存
         */
        List<JbsaOrg> beansResult =
            CacheUtil.get(JbsaConstants.CACHE_NAME_ORG, "list_" + para.toJson(), () -> {
                return JbsaOrgController.this.orgService.findPageByKv(page, limit, para);
            }, JbsaConstants.CACHE_LIVE_SECONDS);

        /*
         * 返回Ajax调用的Json结果
         */
        this.renderJson(new LayuiPage(beansResult));
    }

    /**
     * 新增或更新记录
     */
    @PostRequest
    @CacheEvict(name = JbsaConstants.CACHE_NAME_ORG)
    @Before(JbsaResourceValidator.class)
    @RequiresPermissions(value = {"system:org:add", "system:org:edit"})
    @JbsaLog("新增或更新部门")
    public void saveOrUpdate(JbsaOrg bean) {
        this.LOG.info("新增或更新{}记录：bean={}", SERVICE_NAME, bean);

        if (bean.getParentId().equals(bean.getId())) {
            this.renderAjaxFailed(BaseConstants.RETURN_CODE_VALUE_FAILED, "上级资源不能是自己！");
            return;
        }

        // 这里引用事务处理是为了方便Ajax模式处理
        boolean success = Db.tx(new IAtom() {

            Date now = DateUtil.date();
            JbsaAdmin admin = JbsaOrgController.this.getCurrentAdmin();
            JbsaOrg parent = JbsaOrgController.this.orgService.findById(bean.getParentId());

            @Override
            public boolean run() throws SQLException {
                if (ObjectUtil.isNull(bean.getId())) {
                    /*
                     * 新增记录
                     */
                    // 初始化数据
                    bean.setCreatorId(this.admin.getId());
                    bean.setCreatedTime(this.now);
                    bean.setEditorId(this.admin.getId());
                    bean.setEditedTime(this.now);
                    bean.setPathIds(this.parent == null ? "" : this.parent.getPathIds()
                        + (this.parent.getPathIds().length() > 0 ? "," : "") + this.parent.getId());
                    bean.setLayerNum(null == this.parent ? 0 : this.parent.getLayerNum() + 1);

                    // 新建记录到数据库
                    JbsaOrgController.this.orgService.save(bean);

                } else {
                    /*
                     * 修改记录
                     */
                    // 获取已经存在的记录
                    JbsaOrg exist = JbsaOrgController.this.orgService.findById(bean.getId());

                    // 更新数据
                    exist._setAttrs(bean);
                    exist.setEditorId(this.admin.getId());
                    exist.setEditedTime(this.now);

                    // 更新到数据库
                    JbsaOrgController.this.orgService.update(exist);

                    // 更新所有下级项目的状态与当前状态一致
                    JbsaOrgController.this.orgService.updateStatus(exist, exist.getStatus());
                }

                // 更新父对象的子对象ID列表
                JbsaOrgController.this.orgService.updateChildredIds(this.parent);

                return true;
            }
        });

        // 返回Ajax成功
        if (success) {
            this.renderAjaxSuccessed();
        } else {
            this.renderAjaxFailed("操作失败！");
        }
    }

    /**
     * 获取资源树
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:list"})
    public void tree() {
        /*
         * 调用服务模块执行查询，并处理缓存
         */
        LayuiTreeSelect<JbsaOrg> treeResult =
            CacheUtil.get(JbsaConstants.CACHE_NAME_ORG, "tree_{}", new IDataLoader() {
                @Override
                public Object load() {
                    /*
                     * 获取Bean列表
                     */
                    List<JbsaOrg> beanList =
                        JbsaOrgController.this.orgService.findPageByKv(null, null, Kv.create());

                    /**
                     * 通过ID字段名、上级ID字段名、name字段名、顶层ID值生成树
                     */
                    LayuiTreeSelect<JbsaOrg> tree = new LayuiTreeSelect<>(beanList, "id", "parent_id", "name",
                        StrUtil.toString(JbsaOrg.TOP_ID));

                    // 新增顶层Item
                    JbsaOrg bean = new JbsaOrg();
                    bean.setId(JbsaOrg.TOP_ID);
                    bean.setParentId(JbsaOrg.TOP_ID);
                    bean.setName("-- 顶层 --");
                    bean.setSortNum(Integer.MIN_VALUE);

                    tree.add(JbsaOrg.TOP_ID,
                        new LayuiTreeSelect.LayuiTreeSelectItem<>(bean, "id", "parent_id", "name"));

                    return tree;
                }
            }, JbsaConstants.CACHE_LIVE_SECONDS);

        /*
         * 返回Ajax调用的Json结果
         */
        this.renderJson(treeResult);
    }

    /**
     * 跳转到记录展示页面
     */
    @GetRequest
    @RequiresPermissions(value = {"system:org:view"})
    public void view() {
        this.LOG.info("跳转到{}记录展示页面：kv={}", SERVICE_NAME, this.getKv());
        JbsaOrg bean = this.orgService.findById(this.get(0));

        this.setAttr("bean", bean);
    }
}
